/**
 * @author Dylan Jones, Ryan Hammonds
 */
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;


public class StringGenerator implements Iterable<String> {
	protected char[] chars;
	protected char[] out;
	protected int[] track;
	protected int curPosition;
	protected boolean first;
	
	public class GeneratorState {
		protected char[] chars;
		protected char[] out;
		protected int[] track;
		protected int curPosition;
		protected boolean first;
		
		public GeneratorState(char[] chars, char[] out, int[] track, int curPosition, boolean first){
			this.chars = chars;
			this.out = out;
			this.track = track;
			this.curPosition = curPosition;
			this.first = first;
		}
	}
	
	public class GenIterator implements Iterator<String> {

		@Override
		public boolean hasNext() {
			return curPosition>=0;
		}

		@Override
		public String next() {
			if (!hasNext())
				throw new NoSuchElementException();
			return getNextString();
		}

		@Override
		public void remove(){}
	}
	
	
	public StringGenerator(Set<Character> charSet, int length){
		chars = new char[charSet.size()];
		int i = 0;
		for (Character c : charSet) {
			chars[i] = c;
			i++;
		}
		out = new char[length];
		track = new int[length];
		for (i = 0; i < length; i++) {
			out[i] = chars[0];
		}
		curPosition = length-1;
		first = true;
	}
	
	public StringGenerator(GeneratorState state){
		this.curPosition = state.curPosition;
		this.chars = state.chars;
		this.track = state.track;
		this.out = state.out;
		this.first = state.first;
	}
	
	public String getNextString() {
		if(!first){
			boolean backup = false;
			if (track[curPosition] == chars.length - 2 || track[curPosition] == chars.length - 1){
				backup = true;
				for(int j = curPosition+1; j < track.length; j++){
					if(track[curPosition] != chars.length - 1){
						backup = false;
						break;
					}
				}
			}
			if (backup){
				out[curPosition] = chars[++track[curPosition]];
				String temp = String.valueOf(out);
				for (int j = curPosition; j < track.length; j++) {
					track[curPosition] = 0;
					out[curPosition] = chars[0];
				}
				curPosition--;
				while(curPosition >= 0 && track[curPosition] == chars.length - 1){
					for (int j = curPosition; j < track.length; j++) {
						track[curPosition] = 0;
						out[curPosition] = chars[0];
					}
					curPosition--;
				}
				return temp;
			}
			out[curPosition] = chars[++track[curPosition]];
			while(curPosition != out.length-1)
				curPosition++;
			return String.valueOf(out);
		} else {
			first = false;
			return String.valueOf(out);
		}
	}
	
	@SuppressWarnings("unused")
	private void printFields(){
		System.out.print("out:"+String.valueOf(out)+" track:[");
		for(int a : track)
			System.out.print(a+",");
		System.out.println("] position"+curPosition);
	}

	@Override
	public Iterator<String> iterator() {
		return new GenIterator();
	}
}
